package com.us.usws.batch.resimp.channel;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.iwsh.core.exception.GenericRuntimeException;
import net.iwsh.core.exception.TypeMissmatchException;
import net.iwsh.core.utils.IDGenerator;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.supercsv.cellprocessor.Optional;
import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.ift.CellProcessor;

import com.us.usws.batch.BatchUtils;
import com.us.usws.batch.resimp.BatchBdao;
import com.us.usws.batch.resimp.ResDescFile;
import com.us.usws.batch.resimp.ResImpAbstractWorker;
import com.us.usws.batch.resimp.result.ResImpResult;
import com.us.usws.model.flat.channel.DOChannel;

public class CSVChannelImpWorker extends ResImpAbstractWorker<CSVChannel> {

	private static Log log = LogFactory.getFactory().getInstance(CSVChannelImpWorker.class);

	private static final String[] headers = new String[] { "targetRole", "topChannel", "topChannelType", "subChannel",
			"subChannelMeetingType" };

	private Date now = new Date();

	private boolean clean = false;

	public CSVChannelImpWorker(boolean clean) {
		this.clean = clean;
	}

	@Override
	public CellProcessor[] getProcessors() {

		final CellProcessor[] processors = new CellProcessor[] { new NotNull(), // targetRole
				new NotNull(), // topChannel
				new NotNull(), // topChannelType
				new Optional(), // subChannel
				new Optional() // subChannelMeetingType
		};

		return processors;
	}

	@Override
	public String[] getHeaders() {
		return headers;
	}

	private String getKey(CSVChannel each) {
		return each.getTargetRole() + ".#." + each.getTopChannel();
	}

	@Override
	public ResImpResult imp() {
		List<CSVChannel> res = getResults();
		if (res == null) {
			throw new GenericRuntimeException("Please load csv first.");
		}

		//tow maps
		Map<String, DOChannel> topChMap = new HashMap<String, DOChannel>();
		List<DOChannel> subChs = new ArrayList<DOChannel>();

		//loop 1st, get top channels
		int idx = 0;
		for (CSVChannel each : res) {

			String name = each.getTopChannel();
			String csvRole = each.getTargetRole();
			String csvChType = each.getTopChannelType();
			log.info("top:" + name + "," + csvRole + "," + csvChType);
			if (StringUtils.isBlank(name) || StringUtils.isBlank(csvRole) || StringUtils.isBlank(csvChType)) {
				continue;
			}

			String key = getKey(each);
			int targetRole = getTargetRole(csvRole);
			int channelType = getChannelType(csvChType);
			if (topChMap.containsKey(key)) {
				DOChannel mapC = topChMap.get(key);
				if (mapC.getChannelTypeDsid().intValue() != channelType) {
					mapC.setChannelTypeDsid(mapC.getChannelTypeDsid().intValue() | targetRole);
				}
			} else {
				idx++;
				topChMap.put(key, genNewTopChannel(each, idx));
			}
		}

		//loop for sub channels
		idx = 0;
		for (CSVChannel each : res) {
			String name = each.getSubChannel();
			log.info("sub: " + name + " of top [" + each.getTopChannel() + "].");
			if (StringUtils.isBlank(name)) {
				continue;
			}
			idx++;
			String key = getKey(each);
			//int targetRole = getTargetRole(each.getTargetRole());
			//int channelType = getChannelType(each.getTopChannelType());
			if (topChMap.containsKey(key)) {
				log.info("sub? contains " + key);
				DOChannel mapC = topChMap.get(key);
				DOChannel oneC = genNewSubChannel(each, mapC.getSeqNum(), idx);
				oneC.setParentUid(mapC.getUid());
				oneC.setTargetRole(mapC.getTargetRole());
				if (each.getSubChannelMeetingType() != null) {
					oneC.setMettingType(getSubChannelMeetingType(each.getSubChannelMeetingType()));
				}
				subChs.add(oneC);
			} else {
				log.error("Cannot find parent uid of at line " + idx + ".");
			}
		}

		ResImpResult ret = save(topChMap, subChs);

		return ret;
	}

	private ResImpResult save(Map<String, DOChannel> topChMap, List<DOChannel> subChs) {
		ResImpResult ret = new ResImpResult();
		ret.setTitle("批量导入频道");

		BatchBdao dao = new BatchBdao();
		List<DOChannel> list = new ArrayList<>();
		list.addAll(topChMap.values());
		list.addAll(subChs);
		try {
			dao.createChannels(list, this.clean);
			ret.setSuccessCnt(list.size());
			Set<ResDescFile> df = getDescFiles();
			for (ResDescFile one : df) {
				ret.setFilePath(one.getPath());
				break;
			}
			ret.setSummaryMsg("导入成功。");
		} catch (Exception e) {
			ret.setSummaryMsg("保存数据时出错。");
			ret.setEx(e);
		}

		return ret;
	}

	private Integer getSubChannelMeetingType(String type) {
		switch (type) {
		case "在线辅导":
			return 1;
		case "网络教室":
			return 2;
		case "家长会议":
			return 3;
		case "家长访谈":
			return 4;
		default:
			throw new TypeMissmatchException("Invalid meeting type:[" + type + "].");
		}
	}

	private DOChannel genNewTopChannel(CSVChannel each, int idx) {
		DOChannel ret = new DOChannel();
		String uid = IDGenerator.getInstance().genUID();
		ret.setUid(uid);
		ret.setChannelTypeDsid(getChannelType(each.getTopChannelType()));
		ret.setCreateByUid(BatchUtils.ADMIN_UID);
		ret.setCreateDate(now);
		ret.setIsIdxChannel("Y");
		ret.setIsValid("Y");
		ret.setName(each.getTopChannel());
		ret.setParentUid("/");
		ret.setPicture("");
		ret.setSeqNum(idx * 100);
		ret.setTargetRole((long) getTargetRole(each.getTargetRole()));
		return ret;
	}

	private DOChannel genNewSubChannel(CSVChannel each, int parentSeqnum, int idx) {
		DOChannel ret = new DOChannel();
		String uid = IDGenerator.getInstance().genUID();
		ret.setUid(uid);
		ret.setChannelTypeDsid(getChannelType(each.getTopChannelType()));
		ret.setCreateByUid(BatchUtils.ADMIN_UID);
		ret.setCreateDate(now);
		ret.setIsIdxChannel("N");
		ret.setIsValid("Y");
		ret.setPicture("");
		ret.setName(each.getSubChannel());
		ret.setSeqNum(parentSeqnum + idx);
		return ret;
	}

	private int getTargetRole(String roleName) {
		switch (roleName) {
		case "学生":
			return 1;
		case "家长":
			return 2;
		case "公共频道":
			return 4;
		case "老师":
			return 8;
		default:
			throw new TypeMissmatchException("Invalid role:[" + roleName + "].");
		}
	}

	private int getChannelType(String type) {
		switch (type) {
		case "普通频道":
			return 1;
		case "功能":
			return 2;
		case "视频":
			return 3;
		case "会议":
			return 4;
		default:
			throw new TypeMissmatchException("Invalid channel type:[" + type + "].");
		}
	}
}
